package com.pokermind.operator;

import com.pokermind.common.log.PlainLog;
import com.pokermind.common.log.TimeCostLog;
import com.pokermind.model.po.PokerDecisionSnapshot;
import com.pokermind.repository.dao.PokerDecisionSnapshotDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 扑克AI决策业务操作类
 * 处理AI决策相关的业务逻辑
 * 
 * @author PokerMind Team
 */
@Service
public class PokerDecisionOperator {
    
    private static final Logger logger = LoggerFactory.getLogger(PokerDecisionOperator.class);
    
    @Autowired
    private PokerDecisionSnapshotDao pokerDecisionSnapshotDao;
    
    /**
     * 创建决策快照
     * @param userId 用户ID
     * @param handId 手牌ID
     * @param gameState 游戏状态JSON
     * @return 创建的决策快照
     */
    public PokerDecisionSnapshot createDecisionSnapshot(Long userId, Long handId, String gameState) {
        PlainLog plainLog = new TimeCostLog("op", "createDecisionSnapshot")
            .put("userId", userId)
            .put("handId", handId)
            .put("gameStateLength", gameState != null ? gameState.length() : 0);
            
        try {
            // 参数验证
            if (userId == null) {
                throw new IllegalArgumentException("User ID cannot be null");
            }
            if (handId == null) {
                throw new IllegalArgumentException("Hand ID cannot be null");
            }
            if (gameState == null || gameState.trim().isEmpty()) {
                throw new IllegalArgumentException("Game state cannot be null or empty");
            }
            
            // 获取该手牌的下一个快照序号
            long existingCount = pokerDecisionSnapshotDao.countByHandId(handId);
            int nextSequence = (int) (existingCount + 1);
            
            plainLog.put("existingSnapshots", existingCount)
                .put("nextSequence", nextSequence);
            
            // 创建快照
            PokerDecisionSnapshot snapshot = new PokerDecisionSnapshot(userId, handId, nextSequence, gameState);
            PokerDecisionSnapshot savedSnapshot = pokerDecisionSnapshotDao.save(snapshot);
            
            plainLog.put("snapshotId", savedSnapshot.getId())
                .put("createdAt", savedSnapshot.getCreatedAt())
                .put("op_rslt", "done");
                
            logger.info(plainLog.toString());
            return savedSnapshot;
            
        } catch (IllegalArgumentException e) {
            logger.warn(plainLog.put("op_rslt", "param_error:" + e.getMessage()).toString());
            throw e;
        } catch (Exception e) {
            logger.error(plainLog.put("op_rslt", "ex:" + e.getMessage()).toString(), e);
            throw new RuntimeException("Failed to create decision snapshot", e);
        }
    }
    
    /**
     * 更新决策快照的AI分析结果
     * @param snapshotId 快照ID
     * @param recommendation AI推荐
     * @param confidence 置信度
     * @param reasoning 推理过程
     * @return 更新的行数
     */
    public int updateAiAnalysis(Long snapshotId, String recommendation, BigDecimal confidence, String reasoning) {
        PlainLog plainLog = new TimeCostLog("op", "updateAiAnalysis")
            .put("snapshotId", snapshotId)
            .put("recommendation", recommendation)
            .put("confidence", confidence)
            .put("reasoningLength", reasoning != null ? reasoning.length() : 0);
            
        try {
            // 参数验证
            if (snapshotId == null) {
                throw new IllegalArgumentException("Snapshot ID cannot be null");
            }
            
            // 查找快照
            Optional<PokerDecisionSnapshot> snapshotOpt = pokerDecisionSnapshotDao.findById(snapshotId);
            if (snapshotOpt.isPresent()) {
                PokerDecisionSnapshot snapshot = snapshotOpt.get();
                plainLog.put("userId", snapshot.getUserId())
                    .put("handId", snapshot.getHandId())
                    .put("sequence", snapshot.getSnapshotSequence());
                
                // 更新AI分析结果
                snapshot.setAiAnalysis(recommendation, confidence, reasoning);
                int updated = pokerDecisionSnapshotDao.update(snapshot);
                
                plainLog.put("updated", updated).put("op_rslt", "done");
                logger.info(plainLog.toString());
                return updated;
            } else {
                plainLog.put("snapshotFound", false).put("op_rslt", "not_found");
                logger.warn(plainLog.toString());
                return 0;
            }
            
        } catch (IllegalArgumentException e) {
            logger.warn(plainLog.put("op_rslt", "param_error:" + e.getMessage()).toString());
            throw e;
        } catch (Exception e) {
            logger.error(plainLog.put("op_rslt", "ex:" + e.getMessage()).toString(), e);
            throw new RuntimeException("Failed to update AI analysis", e);
        }
    }
    
    /**
     * 根据ID查找决策快照
     * @param snapshotId 快照ID
     * @return 决策快照，如果不存在返回empty
     */
    public Optional<PokerDecisionSnapshot> findSnapshotById(Long snapshotId) {
        return pokerDecisionSnapshotDao.findById(snapshotId);
    }
    
    /**
     * 根据手牌ID和序号查找决策快照
     * @param handId 手牌ID
     * @param sequence 快照序号
     * @return 决策快照，如果不存在返回empty
     */
    public Optional<PokerDecisionSnapshot> findSnapshotByHandIdAndSequence(Long handId, Integer sequence) {
        return pokerDecisionSnapshotDao.findByHandIdAndSequence(handId, sequence);
    }
    
    /**
     * 获取手牌的所有决策快照
     * @param handId 手牌ID
     * @return 决策快照列表
     */
    public List<PokerDecisionSnapshot> getHandSnapshots(Long handId) {
        return pokerDecisionSnapshotDao.findByHandId(handId);
    }
    
    /**
     * 获取用户的决策历史
     * @param userId 用户ID
     * @param limit 返回数量限制
     * @return 决策快照列表
     */
    public List<PokerDecisionSnapshot> getUserDecisionHistory(Long userId, int limit) {
        return pokerDecisionSnapshotDao.findByUserId(userId, limit);
    }
    
    /**
     * 获取用户在指定时间范围内的决策
     * @param userId 用户ID
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 决策快照列表
     */
    public List<PokerDecisionSnapshot> getUserDecisionsInTimeRange(Long userId, LocalDateTime startTime, LocalDateTime endTime) {
        return pokerDecisionSnapshotDao.findByUserIdAndTimeRange(userId, startTime, endTime);
    }
    
    /**
     * 获取有AI推荐的决策快照
     * @param userId 用户ID（可选）
     * @param limit 返回数量限制
     * @return 有AI推荐的决策快照列表
     */
    public List<PokerDecisionSnapshot> getSnapshotsWithAiRecommendation(Long userId, int limit) {
        return pokerDecisionSnapshotDao.findWithAiRecommendation(userId, limit);
    }
    
    /**
     * 获取高置信度的AI推荐
     * @param userId 用户ID（可选）
     * @param minConfidence 最小置信度
     * @param limit 返回数量限制
     * @return 高置信度决策快照列表
     */
    public List<PokerDecisionSnapshot> getHighConfidenceRecommendations(Long userId, BigDecimal minConfidence, int limit) {
        return pokerDecisionSnapshotDao.findHighConfidenceRecommendations(userId, minConfidence, limit);
    }
    
    /**
     * 根据AI推荐类型查找决策快照
     * @param recommendation AI推荐类型
     * @param userId 用户ID（可选）
     * @param limit 返回数量限制
     * @return 决策快照列表
     */
    public List<PokerDecisionSnapshot> getSnapshotsByRecommendation(String recommendation, Long userId, int limit) {
        return pokerDecisionSnapshotDao.findByRecommendation(recommendation, userId, limit);
    }
    
    /**
     * 获取用户最新的决策快照
     * @param userId 用户ID
     * @return 最新的决策快照，如果不存在返回empty
     */
    public Optional<PokerDecisionSnapshot> getLatestUserDecision(Long userId) {
        return pokerDecisionSnapshotDao.findLatestByUserId(userId);
    }
    
    /**
     * 统计用户的决策快照数量
     * @param userId 用户ID
     * @return 决策快照总数
     */
    public long countUserDecisions(Long userId) {
        return pokerDecisionSnapshotDao.countByUserId(userId);
    }
    
    /**
     * 统计手牌的决策快照数量
     * @param handId 手牌ID
     * @return 决策快照数量
     */
    public long countHandDecisions(Long handId) {
        return pokerDecisionSnapshotDao.countByHandId(handId);
    }
    
    /**
     * 分析用户的AI使用统计
     * @param userId 用户ID
     * @return AI使用统计信息
     */
    public AiUsageStats getAiUsageStats(Long userId) {
        List<PokerDecisionSnapshot> allDecisions = pokerDecisionSnapshotDao.findByUserId(userId, Integer.MAX_VALUE);
        
        AiUsageStats stats = new AiUsageStats();
        stats.setTotalDecisions(allDecisions.size());
        
        int withAi = 0;
        int highConfidence = 0;
        BigDecimal totalConfidence = BigDecimal.ZERO;
        int confidenceCount = 0;
        
        for (PokerDecisionSnapshot snapshot : allDecisions) {
            if (snapshot.hasAiAnalysis()) {
                withAi++;
                if (snapshot.getAiConfidence() != null) {
                    totalConfidence = totalConfidence.add(snapshot.getAiConfidence());
                    confidenceCount++;
                    
                    if (snapshot.isHighConfidence()) {
                        highConfidence++;
                    }
                }
            }
        }
        
        stats.setDecisionsWithAi(withAi);
        stats.setHighConfidenceDecisions(highConfidence);
        
        if (confidenceCount > 0) {
            stats.setAverageConfidence(totalConfidence.divide(BigDecimal.valueOf(confidenceCount), 4, BigDecimal.ROUND_HALF_UP));
        } else {
            stats.setAverageConfidence(BigDecimal.ZERO);
        }
        
        return stats;
    }
    
    /**
     * 删除决策快照
     * @param snapshotId 快照ID
     * @return 删除的行数
     */
    public int deleteSnapshot(Long snapshotId) {
        return pokerDecisionSnapshotDao.deleteById(snapshotId);
    }
    
    /**
     * 删除手牌的所有决策快照
     * @param handId 手牌ID
     * @return 删除的行数
     */
    public int deleteHandSnapshots(Long handId) {
        return pokerDecisionSnapshotDao.deleteByHandId(handId);
    }
    
    /**
     * AI使用统计信息类
     */
    public static class AiUsageStats {
        private int totalDecisions;
        private int decisionsWithAi;
        private int highConfidenceDecisions;
        private BigDecimal averageConfidence;
        
        // Getters and Setters
        public int getTotalDecisions() {
            return totalDecisions;
        }
        
        public void setTotalDecisions(int totalDecisions) {
            this.totalDecisions = totalDecisions;
        }
        
        public int getDecisionsWithAi() {
            return decisionsWithAi;
        }
        
        public void setDecisionsWithAi(int decisionsWithAi) {
            this.decisionsWithAi = decisionsWithAi;
        }
        
        public int getHighConfidenceDecisions() {
            return highConfidenceDecisions;
        }
        
        public void setHighConfidenceDecisions(int highConfidenceDecisions) {
            this.highConfidenceDecisions = highConfidenceDecisions;
        }
        
        public BigDecimal getAverageConfidence() {
            return averageConfidence;
        }
        
        public void setAverageConfidence(BigDecimal averageConfidence) {
            this.averageConfidence = averageConfidence;
        }
        
        public double getAiUsageRate() {
            return totalDecisions > 0 ? (double) decisionsWithAi / totalDecisions : 0.0;
        }
        
        public double getHighConfidenceRate() {
            return decisionsWithAi > 0 ? (double) highConfidenceDecisions / decisionsWithAi : 0.0;
        }
    }
}